#!/usr/bin/env bash
#

# path to lua-compiler
DIR=`realpath $0`
DIR=`dirname $DIR`

CC=clang
LIBTOOL="libtool --tag=CC --silent"
RPATH=`pwd`
LLVM_LUAC="./llvm-luac"
PREFIX="@CMAKE_INSTALL_PREFIX@"

# find llvm-luac
if [[ ! -x "$LLVM_LUAC" ]]; then
	LLVM_LUAC="$DIR/llvm-luac"
fi
if [[ ! -x "$LLVM_LUAC" ]]; then
	LLVM_LUAC=`which llvm-luac`
fi

ARCH=
CPU=i686
#CPU=pentium4
#CPU=athlon64
FORCE_CPU="0"
FILE=
FILES=""
OUTPUT_FILE=""
DEBUG="0"
KEEP_TMPS="0"
STATIC="0"
MODE="standalone"
EXPORT_SYMBOLS=" -Wl,-E "
EXTRA_ARGS=
LIBS=

function echo_cmd() {
	CMD="$1"
	shift 1
	echo "$CMD" "$@"
	$CMD "$@"
}

function version() {
	$LLVM_LUAC -version
	exit 0;
}

function usage() {
	echo "USAGE: $0 [options] <script>

OPTIONS:
  -c++             - Compile as C++ code instead of C code.  Requires that the core was
	                     also compiled as C++ code.
  -lua-module      - Compile Lua script into a loadable module instead of a standalone
                       executable.
  -debug           - Turns off all optimizations and turns on debug info.  Both Lua debug
                       info and gcc debug symbols are enabled.
  -keep-tmps       - Don't delete temp. files generated by intermediate stages.  Use only
                       for debuging generated code or if you are really curious!
  -march=<march>   - <march> is passed to llc as '-march=<march>', see llc --version for targets
  -mcpu=<arch>     - <cpu> is passed to gcc as '-march=<cpu>'
  -******          - All other options passed to 'llvm-luac'.  See below for a list of
                       options supported by 'llvm-luac'.

llvm-luac '-help' output:
"
	$LLVM_LUAC -help
	exit 0;
}

# parse command line parameters.
CONSUME=""
for arg in "$@" ; do
	case "$CONSUME" in
	-o)  OUTPUT_FILE=` echo "$arg" | sed -e 's/-o=//'` ;;
	-L)  EXTRA_ARGS="$EXTRA_ARGS -L $arg" ;;
	esac
	if [[ ! -z "$CONSUME" ]]; then
		CONSUME=""
		continue
	fi
	case "$arg" in
	-lua-mod*)  MODE="lua_mod"; EXTRA_ARGS="$EXTRA_ARGS $arg" ;;
	-static)  STATIC="1" ;;
	-c++)  CC=clang++ ;;
	-debug)  DEBUG="1" ;;
	-keep-tmps)  KEEP_TMPS="1" ;;
	-mode=*)  MODE=` echo "$arg" | sed -e 's/-mode=//'` ;;
	-march=*)  ARCH=` echo "$arg" | sed -e 's/-march=//'` ;;
	-mcpu=*)  FORCE_CPU="1"; CPU=` echo "$arg" | sed -e 's/-mcpu=//'` ;;
	-help|--help|-h)  usage ;;
	-version|--version|-v)  version ;;
	-o|-L)  CONSUME="$arg" ;;
	-L*)  EXTRA_ARGS="$EXTRA_ARGS $arg" ;;
	-*)  EXTRA_ARGS="$EXTRA_ARGS $arg" ;;
	*) FILE=${arg/.lua/}; FILES="$FILES $arg" ;;
	esac
done

# find the mode's output file extension.
OUTPUT_EXT=""
case "$MODE" in
	ll) OUTPUT_EXT=".ll" ;;
	lua_mod) OUTPUT_EXT=".so" ;;
esac
if [[ -z "$OUTPUT_FILE" ]]; then
	OUTPUT_FILE="${FILE}${OUTPUT_EXT}"
else
	FILE=${OUTPUT_FILE}
fi

# get source file's path & filename.
FPATH=`dirname ${FILE}`
FNAME=`basename ${FILE}`

# select debug/optimize parameters.
if [[ $DEBUG == "1" ]]; then
	CFLAGS=" -O0 -ggdb "
	LUA_FLAGS=" -O0 -g "
	#LUA_FLAGS=" -O3 -do-not-inline-opcodes "
	#CFLAGS=" -ggdb -O3 -fomit-frame-pointer -pipe -Wall "
else
	LUA_FLAGS=" -O3 -s "
	#LUA_FLAGS=" -O3 -g "
	#CFLAGS=" -ggdb -O3 -fomit-frame-pointer -pipe -Wall "
	CFLAGS=" -O3 -fomit-frame-pointer -pipe "
fi
if [[ ! -z $CPU && $FORCE_CPU == "1" ]]; then
	CFLAGS=" -mcpu=$CPU $LLC_FLAGS "
fi

if [[ ! -z $ARCH && $FORCE_ARCH == "1" ]]; then
	CFLAGS=" -march=$ARCH $LLC_FLAGS "
fi

#
# run llvm-luac to compile Lua source/bytecode to LLVM bitcode.
#
echo_cmd $LLVM_LUAC $EXTRA_ARGS $LUA_FLAGS -bc -o ${FILE}.bc ${FILES} || {
	echo "llvm-luac: failed to compile Lua code into LLVM bitcode."
	exit 1;
}
TMPS="${FILE}.bc"

# use one of the compile modes.
case "$MODE" in
	standalone)
		TMPS="$TMPS ${FILE}_run.s"
		echo_cmd $CC $EXPORT_SYMBOLS $CFLAGS -o ${OUTPUT_FILE} ${FILE}.bc -lm -ldl
		;;
	lua_mod)
		TMPS="$TMPS ${FILE}_mod.s ${FPATH}/${FNAME}.lo ${FPATH}/lib${FNAME}.la"
		# compile assembly code to object file.
		$LIBTOOL --mode=compile $CC $CFLAGS -c -o ${FILE}.lo ${FILE}.bc
		# compile to dynamic module
		if [[ $STATIC == "0" ]]; then
			$LIBTOOL --mode=link $CC -rpath ${RPATH} -o ${FPATH}/lib${FNAME}.la ${FILE}.lo && \
			cp -p ${FPATH}/.libs/lib${FNAME}.so ${RPATH}/${OUTPUT_FILE}
			if [[ $KEEP_TMPS == "0" ]]; then
				$LIBTOOL --mode=clean rm -f $TMPS
			fi
		fi
		;;
	*)
		echo "Invalid compile mode: $MODE"
		;;
esac

if [[ $KEEP_TMPS == "0" ]]; then
	rm -f $TMPS
fi

